package com.missilike.core.utils;

import com.missilike.core.domain.AuthUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.function.Function;


public class JwtUtils implements Serializable {
    protected final static String secret = "MissILike$JwtSecret";

    public static Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

    public static <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }

    private static Claims getAllClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    public static Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    public static String refreshToken(String token) {
        final Claims claims = getAllClaimsFromToken(token);
        claims.setIssuedAt(new Date());
        claims.setExpiration(calculateExpirationDate());

        return Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    protected static Date calculateExpirationDate() {
        return DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(45));
    }


    public static AuthUser getUsernameFromToken(String token) {
        AuthUser user = new AuthUser();
        user.setId(Integer.parseInt(getClaimFromToken(token, Claims::getId)));
        user.setAccount(getClaimFromToken(token, Claims::getSubject));
        return user;
    }

    public static String doGenerateToken(AuthUser subject) {
        return Jwts.builder()
                .setId(subject.getId().toString())
                .setSubject(subject.getAccount())
                .setIssuedAt(new Date())
                .setExpiration(calculateExpirationDate())
                .signWith(SignatureAlgorithm.HS256, secret)
                .compact();
    }

    public static Boolean validateToken(String token, UserDetails userDetails) {
        final AuthUser username = getUsernameFromToken(token);
        return (
                username.getUsername().equals(userDetails.getUsername())
                        && !isTokenExpired(token));
    }
}